/**
 * AxLib v2.1.13
 * Author: WaveF
 * QQ: 298010937
 **/

(function (lib) {

    main();

    function main() {
        if (!$axure || !$) {
            trace('请先加载 $axure 和 jquery！');
            return;
        }

        extendAxure();
        extendJquery();
        extendJS();

        window.AXLIB = window.axlib = {
            layout   : layout,
            table    : table,
            retry    : retry,
            trace    : trace,
            jsonbin  : jsonbin,
            sync     : sync,
            repeater : {
                format      : formatRepeaterData,
                getData     : getRepeaterData,
                getDataOnce : getRepeaterDataOnce,
                addData     : addRepeaterData,
                clear       : clearRepeaterData,
                refresh     : refreshRepeaterData
            }
        };
    }

    function extendAxure() {
        $axure.ex = { fn:{} };

        // 改写并拓展Axure的私有对象
        $axure.internal(function ($ax) {
            // 增强中继器相关方法
            let _getRepeater = function(repeaterId) {
                var repeater;
                $axure(function (obj) {
                    return obj.type == 'repeater';
                }).each(function (obj, id) {
                    if (id == repeaterId) {
                        repeater = obj;
                    }
                });
                return repeater;
            }
            $axure.ex.getRepeaterData = function(repeaterId) {
                var ids = $ax.repeater.getAllItemIds(repeaterId);
                var columns = _getRepeater(repeaterId).dataProps;
                rows = [];
                for (var i = 0, il = ids.length; i < il; i++) {
                    var row = {};
                    for (var j = 0, jl = columns.length; j < jl; j++) {
                        var name = columns[j].toLowerCase();
                        var id = ids[i];
                        if ((typeof (id) == 'string') && (id.indexOf('-') != -1))
                            id = $ax.repeater.getItemIdFromElementId(id);
                        var value = $ax.repeater.getData({}, repeaterId, ids[i], name, 'data');
                        if (typeof (value) == 'object') {
                            value = $ax.deepCopy(value);
                            if (value.type === undefined)
                                value.type = 'text';
                            row[name] = value;
                        } else {
                            row[name] = {
                                type: 'text',
                                text: value
                            };
                        }
                    }
                    rows.push(row);
                }
                return rows;
            };
            $ax.public.fn.exGetRepeaterData = $ax.public.fn.getRepeaterData = function () {
                let result = $axure.ex.getRepeaterData(this.getElementIds()[0]);
                return result;
            };
            $axure.ex.addRepeaterData = function (repeaterId, rows) {
                var event = {
                    targetElement: undefined,
                    srcElement: undefined
                };
                var repeater = _getRepeater(repeaterId);
                var columns = repeater.dataProps;
                for (var i = 0, il = rows.length; i < il; i++) {
                    var source = rows[i];
                    var target = {};
                    for (var j = 0, jl = columns.length; j < jl; j++) {
                        var column = columns[j];
                        var item = source[column];
                        if (item === undefined) {
                            item = {
                                type: 'text',
                                text: ''
                            };
                        } else {
                            item = $ax.deepCopy(item);
                        }
                        target[column] = item;
                    }
                    $ax.repeater.addItem(repeaterId, target, event);
                }
            };
            $ax.public.fn.exAddRepeaterData = $ax.public.fn.addRepeaterData = function (rows) {
                $axure.ex.addRepeaterData(this.getElementIds()[0], rows);
                return this;
            };
            $axure.ex.refreshRepeater = $ax.repeater.refreshRepeater;
            $ax.public.fn.exRefreshRepeater = $ax.public.fn.refreshRepeater = function () {
                $axure.ex.refreshRepeater(this.getElementIds()[0]);
                return this;
            };
            $axure.ex.getRepeaterRows = $ax.repeater.getAllItemIds;
            $ax.public.fn.exGetRepeaterRows = $ax.public.fn.getRepeaterRows = function () {
                return $axure.ex.getRepeaterRows(this.getElementIds()[0]);
            };
            $axure.ex.clearRepeaterData = function (repeaterId) {
                var ids = $axure.ex.getRepeaterRows(repeaterId);
                $ax.repeater.addEditItems(repeaterId, ids);
                $ax.repeater.deleteItems(repeaterId, {}, 'marked', undefined);
            };
            $ax.public.fn.exClearRepeaterData = $ax.public.fn.clearRepeaterData = function () {
                $axure.ex.clearRepeaterData(this.getElementIds()[0]);
                return this;
            };
            
            // 增强动态面板相关方法
            $axure.ex.getPanelStates = function (els) {
                var elementId = els.getElementIds()[0];
                var result = [];
                for (var index = 1;; index++) {
                    var element = $('#' + elementId + '_state' + (index - 1));
                    if (!element.length) break;
                    var name = element.attr('data-label');
                    result[index] = name;
                    result[name] = index;
                }
                return result;
            };
            $ax.public.fn.getPanelStates = $ax.public.fn.getPanelStates = function () {
                $axure.ex.getPanelStates(this);
                return this;
            };
            $axure.ex.setPanelStateByName = function (els, stateName, options, showWhenSet) {
                let ids = els.getElementIds();
                
                for (let i = 0; i < ids.length; i++) {
                    let id = ids[i];
                    let states = $axure.ex.getPanelStates(els);
                    for (let k = 0; k<states.length; k++) {
                        if (states[k] == stateName) {
                            let stateNum = k;
                            $axure('#' + id).SetPanelState(stateNum, options || {}, showWhenSet || false);
                        }
                    }
                }
            };
            $ax.public.fn.setPanelStateByName = $ax.public.fn.setPanelStateByName = function (stateName, options, showWhenSet) {
                $axure.ex.setPanelStateByName(this, stateName, options, showWhenSet);
                return this;
            };

            // 修正axure无法获取全局变量的bug
            $ax.public.getGlobalVariable = $ax.getGlobalVariable = function(name) {
                return $ax.globalVariableProvider.getVariableValue(name);
            };

            // 改写页面跳转方法
            // var nav = $ax.public.navigate;
            // $ax.public.navigate = $ax.navigate = function (url) {
            //     $({
            //         deg: 0
            //     }).animate({
            //         deg: 90
            //     }, {
            //         duration: 300,
            //         step: now => {
            //             $('#base').css('transform', `rotateY(${now}deg)`)
            //         },
            //         complete: () => {
            //             nav(url);
            //         }
            //     });
            // };

        });

    }

    function extendJquery() {
        $.isJSON = function (str) {
            try {
                if (typeof JSON.parse(str) == "object") {
                    return true;
                }
            } catch(e) {}
            return false;
        };

        $.fn.extend({
            'hasAttr': function(name) {
                var _attr = $(this).attr(name);
                if (typeof _attr !== typeof undefined && _attr !== false) {
                    return true;
                } else {
                    return false;
                }
            }
        });
    }

    function extendJS() {
        // 拓展模版字符串的 minify 方法去除换行
        Object.defineProperty(String.prototype, 'minify', {
            enumerable: false,
            configurable: true,
            value: function () {
                return this.replace(/ *[\r|\n] */gm, '')
            }
        });
    }

    function layout(mode) {
        if (self == top) return;
        mode = mode!==undefined?mode:0;

        let _mode = {
            hotspots: false,
            notes: false,
            scale: [0, 1, 2][1],
            console: false,
            sitemap: false,
            minimal: false,
            website: true
        };

        setTimeout(()=>{
            let shell = window.parent.document;
            let hash = shell.location.hash;

            if (mode>0) {
                if (hash.indexOf('&fn=0')<0) { $(shell).find('#showNotesOption').click(); }
                if (hash.indexOf('&hi=1')>-1) { $(shell).find('#showHotspotsOption').click(); }
            }

            if (mode===0) {
                $(shell).find('#maximizePanelContainer').show();
                $(shell).find(`.vpScaleOption[val="0"]`).click();
            } else if (mode===1) {
                $(shell).find(`.vpScaleOption[val="0"]`).click();
                $(shell).find('#interfaceControlFrameMinimizeContainer').click();
                $(shell).find('#maximizePanelContainer').hide();
            } else if (mode===2) {
                $(shell).find(`.vpScaleOption[val="1"]`).click();
                $(shell).find('#interfaceControlFrameMinimizeContainer').click();
                $(shell).find('#maximizePanelContainer').hide();
            } else if (mode===3) {
                $(shell).find(`.vpScaleOption[val="2"]`).click();
                $(shell).find('#interfaceControlFrameMinimizeContainer').click();
                $(shell).find('#maximizePanelContainer').hide();
            }
        }, 0);
    }

    function table(rep, data, opts) {
		let formatData = [];
        let loop = opts===false?1:2;
		for (let n = 0; n < loop; n++) {
			for (let i = 0; i < data.length; i++) {
				let item = {};
				for (let k in data[i]) {
					item[k] = {
						type: 'text',
						text: data[i][k]
					};
				}
				formatData.push(item);
			}
        }
        retry(()=>{ rep.clearRepeaterData(); }, 5);
        retry(()=>{ rep.addRepeaterData(formatData); }, 5);
        rep.refreshRepeater();

        if (opts === false) return;
        opts = opts || {};
        
        let rid = rep.getElementIds()[0];
        let el = document.getElementById(rid);
        let items = $(el).children('div');

        yepnope({
            test: window.anime,
            nope: 'https://cdn.jsdelivr.net/npm/animejs@3.2.1/lib/anime.min.js',
            complete: ()=>{
                let { dir=-1, dur=1000, delay=1000, easing='easeOutCubic' } = opts;

                // TODO: 暂时只支持向上滚动，向下滚动需要修改初始位置和结束点判断
                dir = -1;

                let distance = items.height() * dir;
                let endPoint = (items.length) * distance;

                rep.moveTo(0,0,{});
                anime.remove(`#${rid}`);

                let _scrollList = function (rep) {
                    anime({
                        targets: `#${rid}`,
                        top: `+=${distance}`,
                        duration: dur,
                        delay: delay,
                        loop: false,
                        easing: easing,
                        complete: function(anim) {
                            let top = $(el).position().top;
                            if (top == endPoint/2) {
                                anime.set(`#${rid}`, { top: 0 });
                            }
                            _scrollList(rep);
                        }
                    });
                };
        
                _scrollList(rep, opts);
            }
        });
    }
    
    function jsonbin(options) {
        let host = 'https://api.jsonbin.io';
        let { bin='', name='', apikey='', version=false, secure=false } = options;
        
        return {
            create: function(data, callback) {
                $.ajax({
                    url: `${host}/b`,
                    data: JSON.stringify({ 'data': data }),
                    type: 'POST',
                    beforeSend: function (req) {
                        req.setRequestHeader("private", secure);
                        if (apikey) { req.setRequestHeader("secret-key", apikey); }
                        if (name) { req.setRequestHeader("name", name); }
                    },
                    contentType: 'application/json; charset=utf-8',
                    dataType: 'json',
                    success: function (res) {
                        if (typeof callback == 'function') {
                            callback(res);
                        }
                    },
                    error: function (err) { console.log(err); }
                });
            },
            update: function(data, callback) {
                $.ajax({
                    url: `${host}/b/${bin}`,
                    data: JSON.stringify({ 'data': data }),
                    type: 'PUT',
                    beforeSend: function (req) {
                        req.setRequestHeader("versioning", version);
                        if (apikey) { req.setRequestHeader("secret-key", apikey); }
                    },
                    contentType: 'application/json; charset=utf-8',
                    dataType: 'json',
                    success: function (res) {
                        if (typeof callback == 'function') {
                            callback(res);
                        }
                    },
                    error: function (err) { console.log(err); }
                });
            },
            read: function(callback) {
                $.ajax({
                    url: `${host}/b/${bin}/latest`,
                    type: 'GET',
                    beforeSend: function (req) {
                        if (apikey) {  req.setRequestHeader("secret-key", apikey); }
                    },
                    contentType: 'application/json; charset=utf-8',
                    dataType: 'json',
                    success: function (res) {
                        if (typeof callback == 'function') {
                            callback(res);
                        }
                    },
                    error: function (err) { console.log(err); }
                });
            },
            delete: function(callback) {
                $.ajax({
                    url: `${host}/b/${bin}`,
                    type: 'DELETE',
                    beforeSend: function (req) {
                        if (apikey) { req.setRequestHeader("secret-key", apikey); }
                    },
                    contentType: 'application/json; charset=utf-8',
                    dataType: 'json',
                    success: function (res) {
                        if (typeof callback == 'function') {
                            callback(res);
                        }
                    },
                    error: function (err) { console.log(err); }
                });
            }
        };
    }

    function retry (action, max, error) {
        let count = max;
        if (count == 0) {
            console.log(`retry ${max} times, abort.`);
            return;
        }
        let func = function() {
            try {
                action();
            } catch(err) {
                if (typeof error == 'function') {
                    error(err, max-count);
                }
                count--;
                func();
            }
        };
        func();
    }

    function trace() {
        console.group('%c[axlib]', 'color:#06f; font-weight:bold;');
        console.log(...arguments);
        console.groupEnd()
    }

    function sync(service) {
        service = service || 'axhub';
        if (service == 'axhub') {
            $('#axhub-rp9-root a i', top.document).click();
        }
    }

    function formatRepeaterData(data, method, options) {
        method = method || 1;
        options = options || {};

        if (method == 0) {
            return data;
        }
        else if (method == 1) {
            let arr = [];
            for (let i = 0; i < data.length; i++) {
                let item = data[i];
                let obj = {};
                for (let k in item) {
                    obj[k] = item[k].text;
                }
                arr.push(obj);
            }
            return arr;
        }
        else if (method == 2) {
            let obj = {};
            for (let i = 0; i < data.length; i++) {
                let item = data[i];
                for (k in item) {
                    if (!obj[k]) {
                        obj[k] = [item[k].text];
                    } else {
                        obj[k].push(item[k].text);
                    }
                }
            }
            return obj;
        }
        else if (method == 3) {
            let result = {};
            let single = options.single;
            for (let i = 0; i < data.length; i++) {
                let item = data[i];
                let obj = {};
                let key = Object.values(item)[0].text;
                let val = [];
                for (let k in item) {
                    let sub = item[k];
                    if (sub.text != key) {
                        val.push(sub.text);
                    }
                }
                obj[key] = single?val[0]:val;
                $.extend(result, obj);
            }
            return result;
        }
        else if (method == 4) {
            let result = {};
            let pKey = options.key;
            for (let i = 0; i < data.length; i++) {
                let item = data[i];
                let key = item[pKey].text;
                let val  = [];
                let obj  = {};
                for (let k in item) {
                    if (k != pKey) {
                        val.push(item[k].text);
                    }
                }
                obj[key] = val;
                $.extend(result, obj);
            }
            return result;
        }
    }

    function getRepeaterDataOnce(id) {
        try {
            var result;
            // $axure(`#${id}`).refreshRepeater();
            return window.$axure((function (id) {
                return "repeater" === id.type
            })).each((function (n, i) {
                id === i && (result = n)
            })), result.data;
        } catch (err) {
            return console.error("Error：Can not get repeater data by id " + err);
        }
    }

    function getRepeaterData(id) {
        try {
            return $axure.ex.getRepeaterData(id);
        } catch (err) {
            return console.error("Error：Can not get repeater data by id " + err);
        }
    }

    function addRepeaterData(id, rows) {
        try {
            return $axure.ex.addRepeaterData(id, rows);
        } catch (err) {
            return console.error("Error：Can not add repeater data by id " + err);
        }
    }

    function clearRepeaterData(id) {
        try {
            return $axure.ex.clearRepeaterData(id);
        } catch (err) {
            return console.error("Error：Can not clear repeater data by id " + err);
        }
    }

    function refreshRepeaterData(id) {
        try {
            return $axure.ex.refreshRepeater(id);
        } catch (err) {
            return console.error("Error：Can not refresh repeater data by id " + err);
        }
    }

}(window.AXLIB || {}));